package scene.gameObject 
{
	import event.CommEvent;
	import flash.display.BitmapData;
	import flash.display.Sprite;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.utils.getTimer;
	import resource.ImageResource;
	import scene.map.Map;
	import scene.path.PathFinder;
	import scene.scene.SceneData;
	import utils.clientConst;
	/**
	 * ...
	 * @author carlor
	 */
	public class ActivateObject extends BasicObject
	{
		static protected const XMovePixels: Array = [0, 50, 50, 50, 0, -50, -50, -50];
		static protected const YMovePixels: Array = [-50, -50, 0, 50, 50, 50, 0, -50];
		
		protected var _objectInfo: Object;
		protected var _ui: IActivateObjectUI;

       //action
		protected var _actionStartTime: int;
		protected var _moveStartTime  : int;
		protected var _curAction : int;
		protected var _nextAction: int;
		
		//image
		protected var _frameCount: int;
		protected var _curFrame	 : int;
		
		protected var _frameDelay: int;
		protected var _defenseStartFrame: int;
		protected var _defenseFrameCount : int;
		protected var _overDefense: Boolean;
		
		protected var _actionData: Object;	
		
		// path
		protected var _pathFinder: PathFinder;
		protected var _pathRange : PathFinder;
		protected var _moving: Boolean;
		
		public function ActivateObject(map: Map, owner: SceneData, data: Object, settingData: Object) 
		{
			_pathFinder = new PathFinder(map);
			_pathFinder.init(map.cellData);
			_pathRange  = new PathFinder(map);
			_pathRange.init(map.cellData);
			super(owner, data, settingData);
		}
		
		override public function dispose(): void
		{
			_pathFinder.dispose();
			_pathFinder = null;
			_pathRange.dispose();
			_pathRange = null;
			if (_ui != null) {
				if (_ui is Sprite)
					this.removeChild(Sprite(_ui));
				_ui.dispose();
			}
			_ui = null;
			if (_objectInfo != null) _objectInfo.dispose();
			_objectInfo = null;
			super.dispose();
		}
		
		override protected function init(settingData: Object): void
		{
			super.init(settingData);
			setCurAction(ActionConst.ACTION_STAND);
		}
		
		public function setObjectInfo(data: Object): void
		{
			_objectInfo = data;
			_pathFinder.camp = data.camp;
			_pathRange.camp  = data.camp;
		}
		
		public function setUI(ui: IActivateObjectUI): void
		{
			_ui = ui;
			if (_ui is Sprite)
				this.addChild(Sprite(_ui));
		}
		
		//private function getCurFrame(time: int): int 
		//{
		//	return Math.floor(time / ActionConst.ACTIONTIME);
		//}
		
		private function getActionTime(): int
		{
			var actionTime: int = _actionData.Actions["ActionID-" + _curAction].FrameDelay;
			if (! actionTime || actionTime == 0) actionTime = ActionConst.ACTIONTIME;
			return actionTime;
		}
		
		override public function update(curTime: int): void
		{
			super.update(curTime);
			
			var cf: int = Math.floor((curTime - _actionStartTime) / _frameDelay);
			
			switch (_curAction) {
				case ActionConst.ACTION_MOVE:
					updateMove(curTime);
					break;
				case ActionConst.ACTION_ATTACK:
				case ActionConst.ACTION_SKILL:
					updateAttack(cf, curTime);
					break;
				case ActionConst.ACTION_DEFENSE:
					updateDefense(cf, curTime);
					break;
				//case ActionConst.ACTION_STAND:
				//	setCurFrame(_curFrame+1);
				//	break;
				default:
					if (cf >= _frameCount)
						actionFinished(curTime);
					else
						setCurFrame(cf);
					break;
			}
		}
		
		private function setDir(value: int): void
		{
			_basicData.dir = value;
		}
		
		protected function actionFinished(curTime: int): void
		{
			var nexta: int = ActionConst.ACTION_STAND;
			switch (_curAction) {
				case ActionConst.ACTION_ATTACK:
				case ActionConst.ACTION_SKILL:
				case ActionConst.ACTION_MOVE:
				case ActionConst.ACTION_STAND:
					nexta = ActionConst.ACTION_STAND;
					break;
			}
			setCurAction(nexta);
		}
		
		public function setCurAction(value: int): void
		{
			_actionStartTime = getTimer();
			if (_curAction == value) return;
			if (!_actionData.Actions["ActionID-" + value])
				_curAction = ActionConst.ACTION_STAND;
			else
				_curAction = value;
			_frameCount = _actionData.Actions["ActionID-" + _curAction].FrameCount;
			_frameDelay = getActionTime();
			_defenseStartFrame = _actionData.Actions["ActionID-" + _curAction].DefenseFrame ? _actionData.Actions["ActionID-" + _curAction].DefenseFrame : _frameCount;
			_defenseFrameCount = _actionData.Actions["ActionID-" + _curAction].DefenseCount ? _actionData.Actions["ActionID-" + _curAction].DefenseCount : 1;
			_centerPoint.x = _actionData.Actions["ActionID-" + _curAction].CenterX;
			_centerPoint.y = _actionData.Actions["ActionID-" + _curAction].CenterY;
		}
		
		private function clearNextAction(): void
		{
			_nextAction = 0;
		}
		
		protected function setNextAction(value: int): void
		{
			_nextAction = value;
		}
		
		private function getImage(): BitmapData
		{
			var image: ImageResource = _imageArray[_curAction];
			if (image) {
				var w: Number = image.data.width / _frameCount;
				var h: Number = image.data.height / 8;
				var result: BitmapData = new BitmapData(w, h);
				result.copyPixels(image.data, new Rectangle(w * _curFrame, h * (_basicData.dir - 1), w, h), new Point());
				return result;
			}else
				return null;
		}
		
		protected function setCurFrame(index: int): void
		{
			if (index >= _frameCount) index = 0;
			_curFrame = index;
			if (_bitmap.bitmapData) {
				_bitmap.bitmapData.dispose();
				_bitmap.bitmapData = null;
			}
			_bitmap.bitmapData = getImage();			
		}
		
		//move
		public function moveTo(pos: Point): void
		{
			if (! _pathFinder.moveTo(_basicData.mapPos, pos)) return;
			
			_moveStartTime = getTimer();
			var p: Point = _pathFinder.moveNext(_basicData.mapPos);
			if (p) {
				setCurAction(ActionConst.ACTION_MOVE);
				setDir(getMoveDir(p));
				setCurFrame(_curFrame);
				_moving = true;
			}
		}
		
		private function updateMove(curTime: int): void
		{
			var moveDelay: int = 300;
			if (curTime - _actionStartTime > moveDelay) {
				moveNext(_actionStartTime + moveDelay);
				return;
			}
			
			var bitTime: int = curTime - _actionStartTime;
			var p: Point = new Point(_basicData.mapPos.x * clientConst.CELLWIDTH, _basicData.mapPos.y * clientConst.CELLHEIGHT);
			var a: int = Math.floor(XMovePixels[_basicData.dir - 1] * bitTime / moveDelay);
			var b: int = Math.floor(YMovePixels[_basicData.dir - 1] * bitTime / moveDelay);
			
			p.x += a;
			p.y += b;
			
			setPosition(p.x, p.y);
			
			var cf: int = Math.floor((curTime - _moveStartTime) / (_frameDelay * moveDelay / 300));
			if (cf >= _frameCount) {
				_moveStartTime = curTime;
				cf = 0;
			}
			if (cf != _curFrame)
				setCurFrame(cf);
		}
		
		private function getMoveDir(p: Point): int
		{
			if (p.x > _basicData.mapPos.x) {
				return ActionConst.DIR_E;
			}
			else if (p.x < _basicData.mapPos.x) {
				return ActionConst.DIR_W;
			}
			else if (p.y > _basicData.mapPos.y) {
				return ActionConst.DIR_S;
			}
			else if (p.y < _basicData.mapPos.y) {
				return ActionConst.DIR_N;
			}else
				return _basicData.dir;
		}
		
		private function moveNext(curTime: int): Boolean
		{
			var arrived: Boolean;
			var p: Point = _pathFinder.moveNext(_basicData.mapPos);
			if (p) {
				setMapPos(p.x, p.y);
				arrived = (p.x == _pathFinder.targetPos.x && p.y == _pathFinder.targetPos.y);
				if (! arrived) {
					setCurAction(ActionConst.ACTION_MOVE);
					setDir(getMoveDir(_pathFinder.moveNext(_basicData.mapPos)));
				}
				else {
					setCurAction(ActionConst.ACTION_STAND);
					setDir(getMoveDir(p));
					setPosition(_basicData.mapPos.x * clientConst.CELLWIDTH, _basicData.mapPos.y * clientConst.CELLHEIGHT);
					actionFinished(curTime);	
					this.dispatchEvent(new CommEvent(CommEvent.MOVE_ARRIVED));
					_moving = false;
				}
			}else {
				setCurAction(ActionConst.ACTION_STAND);
				actionFinished(curTime);	
				this.dispatchEvent(new CommEvent(CommEvent.MOVE_ARRIVED));
				_moving = false;
			}
			
			return p != null && !arrived;
		}
		
		//Attack
		private function getAttackDir(p: Point): int
		{
			if (p.x > _basicData.mapPos.x) {
				if (p.y > _basicData.mapPos.y)
					return ActionConst.DIR_ES
				else if (p.y < _basicData.mapPos.y)
					return ActionConst.DIR_EN
				else
					return ActionConst.DIR_E;
			}
			else if (p.x < _basicData.mapPos.x) {
				if (p.y > _basicData.mapPos.y)
					return ActionConst.DIR_WS
				else if (p.y < _basicData.mapPos.y)
					return ActionConst.DIR_WN
				else
					return ActionConst.DIR_W;
			}else {
				if (p.y > _basicData.mapPos.y)
					return ActionConst.DIR_S
				else if (p.y < _basicData.mapPos.y)
					return ActionConst.DIR_N
				else
					return ActionConst.DIR_S;		
			}
		}
		
		public function attack(target: BasicObject): void
		{
			setCurAction(ActionConst.ACTION_ATTACK);
			setDir(getAttackDir(target.basicData.mapPos));
		}
		
		private function updateAttack(frameIndex: int, curTime: int): void
		{
			if (frameIndex >= _frameCount)
				actionFinished(curTime)
			else {
				setCurFrame(frameIndex);
				
				//hit frame
			}
		}
		
		//defense
		public function defense(): void
		{
			_overDefense = false;
			setCurAction(ActionConst.ACTION_DEFENSE);
		}
		
		public function overDefense(): void
		{
			if (_curAction != ActionConst.ACTION_DEFENSE) return;
			
			_actionStartTime = getTimer();
			_overDefense = true;
		}
		
		private function updateDefense(frameIndex: int, curTime: int): void
		{
			if (! _overDefense) {
				var time: int = curTime - _actionStartTime;
				var dfStartTime: int = _defenseStartFrame * _frameDelay;
				var dfOverTime : int = (_defenseStartFrame + _defenseFrameCount - 1) * _frameDelay;
				while (time > dfOverTime) {
					time = time - dfStartTime;
					if (time < dfStartTime)
						time = dfStartTime;
				}
				
				setCurFrame(Math.floor(time / _frameDelay));
			}else {
				frameIndex = frameIndex + _defenseStartFrame + _defenseFrameCount - 1;
				if (frameIndex >= _frameCount)
					actionFinished(curTime)
				else
					setCurFrame(frameIndex);
			}

		}
		
		public function get objectInfo(): Object
		{
			return _objectInfo;
		}
		
		public function get ui(): IActivateObjectUI
		{
			return _ui;
		}
		
		public function addBlock(pos: Point, camp: int): void
		{
			this._pathFinder.addBlock(pos.x, pos.y, camp);
			this._pathRange.addBlock(pos.x, pos.y, camp);
		}
		
		public function deleteBlock(pos: Point): void
		{
			this._pathFinder.deleteBlock(pos.x, pos.y);
			this._pathRange.deleteBlock(pos.x, pos.y);
		}
		
		public function getMoveRange(): Array
		{
			return this._pathRange.getRange(this.basicData.mapPos,  this.basicData.job, this.objectInfo.moveRange, true);
		}
		
		public function getAttackRange(): Array
		{
			return this._pathRange.getRange(this.basicData.mapPos,  this.basicData.job, this.objectInfo.attackRange, false);
		}
		
		public function clearPath(): void
		{
			this._pathFinder.clear();
			setCurAction(ActionConst.ACTION_STAND);		
		}
		
		public function get moving(): Boolean
		{
			return _moving;
		}
		
		public function set moving(value: Boolean): void
		{
			_moving = value;
		}
	}

}